Skip to content

feat: make sessions worktree-aware - #642

Open
pascalandr wants to merge 20 commits into
NeuralNomadsAI:devfrom
pascalandr:feat/issue-319-session-worktrees
Open

feat: make sessions worktree-aware#642
pascalandr wants to merge 20 commits into
NeuralNomadsAI:devfrom
pascalandr:feat/issue-319-session-worktrees

Conversation

@pascalandr

@pascalandr pascalandr commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • preserve each session's native OpenCode workspace and directory across hydration, creation, duplication, and reloads
  • move complete session families between Git worktrees through OpenCode's native workspace warp API, with lazy migration from legacy CodeNomad metadata
  • add session sorting and worktree filtering plus a desktop-only action to open verified worktree directories in the system file manager
  • harden worktree deletion and concurrent moves with authoritative rescans, family-level serialization, fail-closed checks, and rollback

Implementation

Git remains authoritative for the worktree inventory while OpenCode remains authoritative for session locations. Legacy metadata.codenomad.worktreeSlug values and the local session map are read only for migration, then removed transactionally after a successful native move.

Session families move as a unit. The UI rejects incomplete family resolution, serializes concurrent operations per family, refreshes authoritative OpenCode state after warps, and restores prior locations and metadata if preparation or deletion fails.

The file-manager bridge is exposed only to local Electron and Tauri windows. Native handlers reject remote callers and UNC paths, canonicalize the requested directory, and require an exact match in git worktree list --porcelain -z before invoking the platform shell.

Windows CI exposed the existing cross-host legacy-marker publication race fixed by commit 8379098 from #618. This branch includes that targeted bounded-rescan fix and its deterministic regression test so Electron and Tauri cannot both remain secondary during simultaneous startup. The Windows crate runs serially because these tests launch real Node and PowerShell processes; each test still exercises its intended internal concurrency.

Validation

  • npm run build --workspace @codenomad/ui
  • npm run typecheck
  • npm run typecheck --workspace @neuralnomads/codenomad
  • 118 Electron native tests
  • 40 focused UI tests
  • 34 restore-ownership integration tests
  • 5 server worktree-metadata tests
  • 85 Tauri tests on Windows locally and in GitHub CI
  • cross-host startup race test passed 10 consecutive Windows runs
  • cargo check
  • focused rustfmt --check
  • git diff --check upstream/dev...HEAD

Closes #319

Keep OpenCode project, workspace, and directory identity in CodeNomad session state across list hydration, creation, forks, and session update events.

Resolve worktree labels from the native session directory when OpenCode reports a workspace, while retaining the legacy metadata mapping as a migration fallback. Normalize Windows and POSIX path matching and cover native directory resolution with focused tests.

Validated with the UI typecheck, focused OpenCode workspace matching tests, and git diff checks.
Create new sessions in the active OpenCode workspace and warp existing session families when users select another Git worktree. Route prompts, commands, compaction, reverts, files, Git status, interruption replies, and destructive session operations through the resolved native workspace so unresolved locations fail closed instead of falling back to the project root.

Keep the historical CodeNomad worktree slug only as a lazy migration hint. Successful warps clear that metadata, update runtime location state, and remove legacy map entries; partial family moves roll back before any local state changes. Worktree deletion now refuses to proceed unless affected sessions move safely to root.

Allow metadata markers to be removed in the server persistence layer while preserving unrelated metadata and resolving the session's current workspace before writes. Add focused tests for metadata removal, family migration, and rollback, and validate UI/server typechecks plus related store tests.
Add an accessible session-list menu for recent-activity, name, and native-worktree sorting plus per-worktree filtering. Keep families intact, apply projection after search, and align rendering, bulk selection, and deletion fallback with the visible result.

Expose an Open in file manager action only in local Electron and Tauri desktop windows. Both native bridges validate the sender, reject network paths, canonicalize the requested directory, and verify it against Git's authoritative worktree inventory before invoking the system file manager.

Harden worktree moves and deletion around the new UI: serialize family warps, refresh authoritative OpenCode locations, reject incomplete families, normalize Windows paths, block new worktree operations during deletion, and roll back physical locations and legacy metadata when preparation or Git deletion fails. Serialize legacy map updates and keep post-delete map cleanup best-effort.

Add translated labels for every locale, focused migration/sorting/rollback tests to PR CI, and validate production UI build, all TypeScript typechecks, 118 Electron native tests, 40 focused UI tests, 5 server metadata tests, Tauri cargo check, and Rust formatting.
Allow legacy permission and question responses to use the root client when their session has not been hydrated yet, matching the existing SSE lifecycle. Keep strict native workspace resolution for loaded sessions so worktree-scoped requests still route through their authoritative OpenCode location.

Reproduced the PR restore-ownership integration command locally and verified all 34 tests plus the UI typecheck.
A concurrently starting modern Electron client can publish its legacy running marker just before its cross-host participant. On slower Windows runners, Tauri could observe that transient state and both clients could remain secondary.

Recheck a blocking legacy marker once after a bounded 50 ms grace period while preserving PID, process identity, and executable validation. Add a deterministic participant-publication race test.

Validated with rustfmt, five cross-host startup runs, and the complete 85-test Tauri suite on Windows.
Run the Windows Tauri suite with one Rust test thread because several cross-host tests intentionally launch real Node and PowerShell processes. Parallel crate execution causes unrelated child-process starvation on GitHub's Windows runner while each test already exercises its own intended concurrency.

Validated the exact CI command locally with all 85 Tauri tests passing.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/31318727230

Artifacts expire in 7 days.
Artifacts:

  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-macos
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-windows
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-macos-arm64
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-electron-macos
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-linux
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-electron-linux
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-electron-windows

1 similar comment
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/31318727230

Artifacts expire in 7 days.
Artifacts:

  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-macos
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-windows
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-macos-arm64
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-electron-macos
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-tauri-linux
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-electron-linux
  • pr-642-7285cf5fdaa1d2421218e0f525f1ad01afd88b8e-electron-windows

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gatekeeper autonome - cycle 1

HEAD: 7285cf5

Findings:

  1. P1 - Les interruptions legacy des sessions occupées déclenchent une migration et peuvent bloquer permission, question et abort. Le contrôle doit utiliser la localisation native courante sans migration.
  2. P1 - Les réponses Yolo serveur omettent le workspace après un warp natif et ciblent root.
  3. P1 - La suppression ignore une famille dont seul un descendant reste dans le worktree cible.
  4. P1 - Le verrou de suppression est local au renderer; une autre fenêtre peut créer ou déplacer une session pendant la suppression.
  5. P1 - Une réponse DELETE perdue déclenche un rollback vers un worktree déjà supprimé.
  6. P1 - Une réponse de warp ambiguë peut scinder une famille tout en laissant le cache local obsolète.
  7. P2 - Les requêtes workspace-scoped ne conservent pas le lease familial jusqu'à la fin de l'opération.
  8. P2 - Une suppression Git échouée peut effacer définitivement un binding legacy virtuel.
  9. P2 - Le cache workspace Yolo reste obsolète lorsqu'une session revient vers root.
  10. P2 - Les opérations root échouent si l'hydratation des worktrees est indisponible.
  11. P2 - Navigation et fallback après bulk-delete ignorent la projection triée/filtrée affichée.
  12. P2 - repoRoot fourni par le renderer est utilisé comme autorité native pour ouvrir un dossier.
  13. P2 - La commande Tauri est accessible à un contenu localhost arbitraire sans validation de l'origine active.
  14. P3 - Electron valide le chemin canonique mais ouvre le chemin mutable original.
  15. P3 - Les worktrees UNC valides sont reconnus par l'UI mais systématiquement rejetés par l'action d'ouverture.

La review sera répétée sur chaque nouveau HEAD jusqu'à zéro finding.

Route workspace-scoped operations through per-family reader/writer leases so requests may proceed concurrently while moves remain exclusive. Reconcile ambiguous warps from authoritative OpenCode project state, preserve busy legacy control requests, support root without Git hydration, and carry authoritative workspace locations into server-side Yolo replies.

Move worktree deletion coordination into the shared server. Drain admitted mutations, reject new writes during deletion, select families from every authoritative member, reconcile uncertain warps, roll back before the Git commit point, and clean legacy bindings only after successful removal. Renderer timeout recovery now checks authoritative Git inventory instead of warping toward a potentially deleted directory.

Resolve desktop folder-open requests from authenticated backend workspace inventory rather than renderer paths. Electron opens only the canonical managed directory; Tauri additionally validates the claimed renderer token and committed origin. Keep UNC opening disabled and hide the unsupported action.

Use the live rendered session projection for navigation and deletion fallback. Add focused regression coverage across UI routing, deletion, Yolo, Electron, and Tauri; validated 55 UI tests, 44 server tests, 122 Electron tests, 88 Tauri tests, all typechecks, and the production UI build.

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gatekeeper autonome - cycle 2

HEAD: 7b35196

Findings:

  1. P1 - Le lease des mutations proxy est libéré dès le retour synchrone de reply.from, avant la fin de la requête upstream.
  2. P1 - La transaction de suppression ne vérifie pas les statuts autoritaires working/compacting sous exclusivité.
  3. P1 - Les prompts directs du gestionnaire de processus de fond contournent le gate partagé.
  4. P1 - Le move familial reste coordonné uniquement dans le renderer; deux clients peuvent intercaler leurs warps.
  5. P2 - Une génération acceptée mais pas encore reflétée par SSE peut être déplacée.
  6. P1 - Un workspaceId natif non résolu retombe à tort sur metadata/map legacy.
  7. P1 - La migration legacy peut réécrire un slug obsolète pendant un move.
  8. P2 - L'écriture du binding session-worktree contourne la coordination de suppression et n'exige pas que le slug existe.
  9. P2 - La création de worktree peut courir avec la fin de suppression du même slug.
  10. P2 - Un PUT de map complet et obsolète peut annuler le nettoyage de suppression.
  11. P1 - Le client reqwest Tauri peut envoyer le cookie loopback via un proxy configuré; il doit utiliser no_proxy.
  12. P3 - La normalisation d'une racine Windows C:\ en C: perd la comparaison insensible à la casse.

Un troisième cycle indépendant sera lancé après correction et publication.

Execute complete family moves through one server-authoritative operation under the shared per-instance gate. Resolve complete ancestry and native targets, reject active or pending families, reconcile every member before returning, and clear legacy metadata/map bindings only after the native move commits.

Hold proxied and direct server mutation leases through actual request completion. Serialize worktree creation, binding writes, map updates, moves, and deletion; validate slugs while admitted and use map revisions to reject stale full-document writes.

Keep native workspace IDs authoritative in the UI, remove eager legacy migration, and apply only reconciled server move responses to local caches. Preserve Windows drive roots during path normalization and prevent Tauri loopback cookie requests from using configured proxies.

Validated 52 focused UI tests, 59 focused server tests, 122 Electron tests, 88 Tauri tests, all typechecks, cargo check, and the production UI build.

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gatekeeper autonome - cycle 3

HEAD: 4177fa1

Findings:

  1. P1 - Une déconnexion client libère encore le gate avant que la mutation upstream soit confirmée terminée ou annulée.
  2. P1 - Un échec de nettoyage metadata/map après les warps laisse les nouvelles localisations commitées sans rollback transactionnel.
  3. P2 - Le prompt de fin de processus attend le gate mais réutilise ensuite un directory capturé avant un move/suppression.
  4. P2 - Une ancienne réponse HTTP de move peut écraser un événement session.updated plus récent provenant d'un autre client.
  5. P2 - Un move réussi vers root ne nettoie pas immédiatement le worktreeSlug legacy dans l'état local et peut afficher/réutiliser feature.

Le cycle 4 relira le nouveau HEAD complet après correction.

Keep proxy mutation admission until the upstream response or error is confirmed, even if the downstream client disconnects. Resolve background completion prompts from authoritative session location only after acquiring mutation admission.

Treat family movement and legacy cleanup as one transaction. Restore metadata, revisioned map state, and native member locations when post-warp cleanup fails, and aggregate rollback failures instead of returning partial success.

Track authoritative session-location epochs in the UI so older move responses cannot overwrite newer cross-client session events. Clear local legacy worktree metadata immediately after a reconciled move, including moves back to root.

Validated 53 focused UI tests, 63 focused server tests, and all UI, Electron, and server typechecks.

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gatekeeper autonome - cycle 4

HEAD: 8eccaf8

Findings:

  1. P1 - Les listeners HTTP/HTTPS ont des gates distincts et les réponses Yolo directes les contournent.
  2. P1 - Une requête proxy interrompue avant headers peut ne déclencher aucun finalizer upstream et fuiter le lease.
  3. P1 - Une suppression peut orpheliner les sessions d'une autre instance live du même dépôt.
  4. P1 - Le CAS de map partagé par dépôt est verrouillé seulement par workspace ID.
  5. P1 - Une map malformée est convertie en fallback puis écrasée pendant la suppression.
  6. P1 - La suppression ne nettoie pas les autres bindings legacy des familles déplacées.
  7. P1 - Search et hydratation de parent-chain peuvent restaurer une ancienne localisation après session.updated.
  8. P2 - La garde de suppression se lève avant réconciliation autoritaire des sessions/workspaces/map.
  9. P2 - Une interruption legacy reçue avant hydratation de session est encore envoyée vers root.
  10. P2 - Fermer la sidebar démonte la projection alors que tri/filtre persistent, et la navigation redevient non filtrée.
  11. P2 - Les chemins Windows étendus équivalents ne sont pas normalisés pour l'identité workspace.

Le cycle 5 sera lancé après publication des corrections.

Route HTTP, HTTPS, background prompt, and Yolo mutations through the same process-wide repository gate so concurrent session moves and destructive operations cannot bypass serialization.

Keep worktree deletion and map updates authoritative across live instances, reject shared-repository deletion, guard asynchronous UI reconciliation with epochs, and preserve navigation projections while the sidebar is closed.

Add focused server and UI regression coverage for proxy lifecycle, strict map reads, canonical repository locking, early request interruption, deletion reconciliation, and stale workspace hydration.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 5\n\nReview target: \c76c1480\n\n1. High Repository mutation identity uses --show-toplevel, so linked worktrees receive different locks and live sibling detection can miss the instance being deleted (\workspace-identity.ts:21-23, \

outes/worktrees.ts:161-169).\n2. High Workspace creation, explicit teardown, and shutdown do not consistently acquire the shared repository/instance mutation gate, allowing runtime startup or stop to race family moves and worktree deletion (
outes/workspaces.ts:75-115, \shutdown.ts:78-99).\n3. High The deletion safety snapshot excludes unpublished starts and retained processes after stop failure (\manager.ts:148-155,337-340,441-480).\n4. High Mutations queued behind an exclusive move retain their stale workspace query and same-repository sibling instances do not share repository read admission (\http-server.ts:663-674).\n5. High The mutation proxy aborts all mutating requests after 120 seconds, including valid long-running command/shell requests (\instance-mutation-proxy.ts:3,18-19).\n6. Medium Worktree-family discovery trusts a matching directory even when \workspaceID\ explicitly identifies another workspace (\worktree-session-move.ts:142-150).\n7. Medium Yolo metadata persistence still mutates sessions outside the shared gate (\�uto-accept-manager.ts:173-210,305-325).\n8. Medium Rollback rewrites and advances an untouched map when metadata clearing fails before the map write (\worktree-session-move.ts:284-312).\n9. Medium Rollback-incomplete aggregate failures are returned as HTTP 400 rather than server errors (
outes/worktrees.ts:285-297).\n10. Medium Accepted list reconciliation does not invalidate older search/hydration location epochs, and delayed map reads can regress the cached revision (\session-api.ts:574-705, \worktrees.ts:203-242).\n11. Medium Native session routing can bypass the local deletion fence, and failed post-delete reconciliation releases that fence while stale locations remain usable (\session-worktree-binding.ts:223-267, \worktrees.ts:177-190).\n12. Medium Creating a session from the active session snapshots its worktree before asynchronous operations without a family read lease (\session-api.ts:783-820).\n13. Medium Electron does not revalidate frame/backend authority immediately before \shell.openPath, and Windows mapped remote drives bypass the UNC prohibition in both native clients (\�lectron/main/ipc.ts:92-104, native worktree-directory modules).\n14. Low Pinning/unpinning remounts the sidebar and resets sort/filter state (\SessionSidebar.tsx:61-62, \instance-shell2.tsx:627-725).\n15. Low New projection and deletion-fence regression suites are absent from the explicit PR workflow test lists (.github/workflows/pr-build.yml:104-141).

Identify linked worktrees by their canonical Git common directory and hold shared repository admission across workspace startup, shutdown, proxy mutations, Yolo persistence, family moves, and destructive cleanup.

Re-resolve queued mutations after exclusive moves, preserve rollback and map revision semantics, retain UI deletion and location fences through authoritative reconciliation, and keep sidebar projection state stable across layout changes.

Revalidate Electron authority before opening canonical folders, reject mapped Windows network drives in both desktop clients, and add focused server, UI, native, and CI regression coverage for the reviewed races.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 6

Review target: ce4e6b8a

  1. High Native move reconciliation requires both workspaceID and directory, but OpenCode warp updates only workspaceID; valid moves roll back (worktree-session-move.ts:200-204).
  2. High The mutation proxy rejects valid workspace-scoped routes without /session/:id, including POST /session and legacy permission/question replies (instance-mutation-proxy.ts:61-65).
  3. High Directory-only legacy sessions are rewritten to root instead of resolving their native workspace (instance-mutation-proxy.ts:79-81, opencode-replier.ts:47-60).
  4. High A hung proxied mutation can hold admission indefinitely and deadlock graceful shutdown against workspace cleanup and app.close() (http-server.ts:716-731, index.ts:638-641).
  5. Medium Background completion prompts use stale directory after native moves (background-processes/manager.ts:655-668).
  6. Medium Worktree creation/map writes capture a workspace before repository admission and can continue after instance deletion (routes/worktrees.ts:136-147,275-295).
  7. Medium Repository keys stay stale if Git topology changes after workspace launch, and launch timeout excludes repository-admission wait (workspaces/manager.ts:173-175,284).
  8. Medium Linked checkouts use separate map files, defeating repository-wide CAS despite sharing a gate (worktree-map.ts:86-88,133-135).
  9. Medium Operational OpenCode/persistence failures from move/delete routes fall through as HTTP 400 (routes/worktrees.ts:302-318).
  10. Medium Delayed status hydration can overwrite a newer session location because it does not capture the location epoch (session-events.ts:163-223).
  11. Medium Concurrent deletion reconciliation uses an unowned instance Set entry; one operation can release another fence, skip reconciliation, or leave it permanently blocked without retry (ui/stores/worktrees.ts:164,176,198-213).
  12. Medium Closed-sidebar navigation drops the active search projection and can select hidden sessions (SessionSidebar.tsx:83-90).
  13. Medium Same-origin project preview content can reach Electron folder-open authority through the parent preload API (electron/main/worktree-directory.ts:93-94, electron/preload/index.cjs:29).
  14. Medium Native folder lookup pins only backend URL, not live process generation; a process rebinding the port after CLI exit can answer authenticated lookup (Electron IPC and Tauri worktree-directory flows).
  15. Medium Native clients need authority revalidation around final dispatch and bounded response streaming; pathname replacement after canonical checks remains a TOCTOU risk.
  16. Medium Server location matching compares path spellings rather than canonical filesystem identity, missing junction/symlink aliases (worktree-session-move.ts:81-85).

Resolve native session locations from workspace identity before legacy directory fallbacks, carry private mutation context across queued proxy requests, and quiesce active upstream mutations before workspace shutdown.

Share map CAS state through the canonical Git common directory, refresh repository identity at lifecycle boundaries, fence concurrent deletion reconciliation, and retain searched sidebar projections while unmounted.

Isolate Electron previews on a dedicated protocol, pin folder opening to the live CLI generation and renderer authority, cap lookup responses, retain directory identity through dispatch, and cover the reviewed races in server, UI, Electron, Tauri, and CI tests.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 7

Review target: 4810e9c2

  1. High Moving a native session to root accepts a cleared workspaceID while its directory still points at the worktree; legacy directory-only sessions can also be incorrectly considered rooted (worktree-session-move.ts:200-203).
  2. High Separate CodeNomad server processes do not share repository mutation admission, so one can create/move sessions while another removes the worktree and its native workspace (worktree-deletion.ts:93-99).
  3. High WSL native Linux paths do not match retained Windows/UNC workspace paths, breaking authoritative resolution (native-session-location.ts:32).
  4. High Client disconnect is observed only after gate admission, and shutdown drain releases leases before upstream settlement (http-server.ts:689, instance-mutation-proxy.ts:136-139).
  5. High codenomad-preview:// forwards arbitrary backend paths with authentication, granting preview scripts API authority (preview-protocol.ts:15,58-71).
  6. High Caller-controlled directory can survive proxy admission for another workspace and execute outside the admitted repository (instance-mutation-proxy.ts:72-110).
  7. High Runtime exit clears PID/port before descendant cleanup is confirmed, allowing destructive repository operations while owned descendants remain (workspaces/manager.ts:973-978).
  8. Medium Session creation sends workspace in both rewritable query and stale request body (ui/stores/session-api.ts:846).
  9. Medium Canonical map CAS and lazy migration lack an interprocess lock; concurrent servers can lose writes or migrate stale bytes over newer state (worktree-map.ts, routes/worktrees.ts).
  10. Medium Deletion reconciliation retry cannot reschedule itself because the current timer remains registered (ui/stores/worktrees.ts:220-230).
  11. Medium Mutation uploads bypass body limits and can hold repository admission indefinitely (http-server.ts:550-551,747-754).
  12. Medium Epoch mismatch with an unloaded descendant still accepts stale hydration, and family leases survive instance lifecycle replacement (session-api.ts:250, session-worktree-binding.ts:19).
  13. Medium Preview isolation is applied to remote Electron windows, address-bar navigation loses the custom authority, and comment mode remains enabled despite cross-origin access being unavailable.
  14. Medium Final renderer authority checks still precede asynchronous filesystem revalidation; Tauri also needs final-handle UNC/remote checks for intermediate junctions.
  15. Medium Delayed pre-move session.updated events can overwrite a committed move without a monotonic location revision (session-events.ts:488-492).
  16. Medium Repository identity transitions can split active admissions between lexical and Git-common-dir keys (manager.ts, workspace-identity.ts).
  17. Low Expected non-Git/dirty-worktree refusals are misclassified as 500, and Windows native identity plus directory-path tests are absent from their effective CI jobs.

Protect repository session, map, and destructive operations with an abortable cross-process lock rooted in the canonical Git common directory, while retaining lexical authority during repository identity transitions.

Move native sessions through the OpenCode control plane, normalize WSL locations, reject abandoned or oversized mutations before forwarding, and keep runtime blockers until descendant cleanup is confirmed.

Scope preview protocols per token, preserve renderer and directory identity through native dispatch, fence UI locations and leases by lifecycle generation, and extend Windows plus cross-process CI coverage.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 8

Review target: d50b06bc

  1. High Cross-process lock stale recovery and release are not atomic; a delayed waiter/releaser can rename or remove a replacement owner lock (repository-mutation-lock.ts:67-77).
  2. High WSL host paths and OpenCode-native Linux paths remain conflated in proxy admission and session move/map transactions (instance-mutation-proxy.ts:47-50, routes/worktrees.ts:308).
  3. High Abort after admission but before upstream handoff leaks instance/repository admission indefinitely (http-server.ts:837-869).
  4. High Worktree deletion checks only current-process workspaces; another server process can hold a live instance after releasing its mutation lock (manager.ts:187-197, routes/worktrees.ts:250).
  5. High Clone replacement with cleanup bypasses repository admission/occupancy and can replace a live workspace directory (routes/workspaces.ts:116-120).
  6. High Canonical map migration ignores legacy maps in other linked worktrees, losing persisted bindings (worktree-map.ts:134-163).
  7. High UI deletion callbacks are not lifecycle-scoped and can execute after reconnect with the same instance ID (ui/stores/worktrees.ts:187).
  8. Medium Lock ownership uses PID-only liveness, temp lock roots lack private/symlink validation, abort reasons are not preserved, and recovery publication is not atomic.
  9. Medium Workspace delete aborts lifecycle before cancellable lock admission; cancellation while queued can strand a live workspace (manager.ts:595-617).
  10. Medium Proxy release callback does not await repository release; mutation upload cap/error handling can reject valid encoded attachments or reset sockets instead of returning 408/413.
  11. Medium WSL-native path comparisons use Windows case-insensitive normalization (worktree-session-move.ts, native-session-location.ts).
  12. Medium File writes/stage/unstage/commit bypass repository admission, allowing concurrent worktree removal (routes/workspaces.ts:215-310).
  13. Medium Deletion reconciliation retries at zero delay indefinitely; search, active family moves, and deletion queues are not fully invalidated by instance lifecycle replacement.
  14. Medium Delayed location confirmation can clear predecessor protection, allowing a later pre-move SSE event to revert location; browser and server timestamps are also compared across different clocks.
  15. Medium Permission/question family routing can fail when the parent chain is not loaded (ui/stores/instances.ts:220).
  16. Medium Preview isolation breaks root-relative paths, WebSockets, SideCar-relative navigation and comment mode; Tauri previews remain same-origin and can trigger parent native actions.
  17. Medium Electron Windows directory identity uses unsafe numeric dev/inode and directory lookup lacks idle/total response deadlines.
  18. Low Duplicate/map conflicts should be 409 and Windows CI still needs the complete Electron native suite.

Make repository lock recovery and release ownership-safe with immutable process identity, private fallback roots, and atomically detached stale records, then track workspace lifetime leases across CodeNomad processes.

Separate host and WSL-native paths through admission, map migration, and control-plane moves; serialize clone and Git file mutations; preserve admission handoff and streamed HTTP error responses.

Scope UI deletion, search, interruption, and family operations to lifecycle generations, replace eager retries with backoff, simplify previews to sandboxed HTTP frames, and retain bigint directory identity plus native response deadlines.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 9

Review target: 2398a6a9

  1. High Workspace creation can deadlock with cancellation/shutdown while lifetime-lease acquisition and instance/repository locks are taken in opposite order (manager.ts:388,644).
  2. High Synchronous prompts retain repository admission until completion, so permission/question replies queue behind the prompt they must unblock (instance-mutation-proxy.ts:209).
  3. High Mutation/lease fallback namespaces depend on process-local TEMP/TMPDIR; servers with different environments bypass each other.
  4. High Missing destinations below symlinked parents derive different lexical identities, allowing concurrent clone cleanup (workspace-identity.ts:50).
  5. High Repository claims on shared UNC/NFS paths can be falsely retired by a different host probing the recorded PID locally (repository-lock-ownership.ts).
  6. High Shutdown during an incomplete mutation upload can leave the connection open and keep app.close() pending (http-server.ts:885-903).
  7. High Location predecessor fencing has no monotonic server revision; rapid consecutive moves plus delayed SSE can still revert the UI.
  8. High Opaque sandboxing applies too broadly and breaks SideCars plus module-script/storage/credentialed preview apps (browser-frame.tsx:218).
  9. Medium Clone occupancy is checked only for cleanup clones; active empty workspace destinations remain mutable.
  10. Medium Repository admission marks release complete before ownership cleanup succeeds, making transient cleanup failures permanent.
  11. Medium Extended WSL UNC aliases bypass shared identity and portable process start probes need timezone-stable identity.
  12. Medium Failed legacy-map cleanup makes migration repeatedly rewrite/revision, while GET masks migration conflicts as an empty HTTP 200 map.
  13. Medium Empty Git worktrees absent from native inventory cannot be deleted; forwarded Expect: 100-continue is unsupported by Undici.
  14. Medium Deletion completion reports failure after authoritative absence when only projection reconciliation is pending; foreground recovery eventually stops retrying.
  15. Medium Native directory lookup deadlines begin after headers or are absent in Tauri; Tauri initial handle identity must match the canonical path.
  16. Low Expected selector move rejection lacks localized feedback.

Keep workspace mutations, leases, and native directory opens authoritative across concurrent processes and Windows/WSL hosts. Control replies can now complete synchronous prompts without weakening admission for unrelated mutations, while confirmed deletions reconcile asynchronously.

Use deterministic private state roots, host-aware heartbeat fences, canonical missing-path locks, strict shared-map migration, monotone session location updates, and document-bound native capabilities. Bound Electron and Tauri directory lookups and close incomplete proxy uploads safely.

Cover lock cleanup and foreign-host expiry, clone admission, map conflicts, rapid session moves, background deletion reconciliation, native capability checks, and request deadlines. Validated server, UI, Electron, and Tauri suites plus typechecks and the UI build.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 10

  1. High packages/server/src/workspaces/repository-mutation-lock.ts:114 changes from the adjacent pre-clone lock to disjoint Git locks once the repository appears, allowing another process to enter before clone completion.
  2. High packages/server/src/workspaces/repository-lock-ownership.ts:163 expires a stalled foreign owner without fencing it, so a suspended owner can resume concurrently.
  3. High packages/server/src/workspaces/workspace-lifetime-lease.ts:33 stores leases in host-local state, so Windows and WSL cannot protect each other's live workspaces.
  4. High packages/server/src/workspaces/repository-mutation-lock.ts:112 hashes host-specific identities for the same missing Windows/WSL destination, allowing concurrent cross-host clones.
  5. High packages/ui/src/stores/session-location-authority.ts:71 accepts a newer delayed pre-move event before move confirmation and can revert the committed move.
  6. High packages/ui/src/stores/session-api.ts:267 does not advance authority when a list confirms the cached location, allowing an older conflicting event afterward.
  7. Medium packages/server/src/workspaces/repository-mutation-lock.ts:162 discards the release handle after one transient cleanup failure, leaving a live heartbeat with no production retry path.
  8. Medium packages/ui/src/components/session-preview-view.tsx:12 retains onInsertComment but BrowserFrame no longer exposes the comment interaction, regressing preview comments.

Keep one adjacent repository lock across clone topology changes and publish workspace leases in repository-visible locations shared by Windows and WSL. Foreign-host claims now fail closed without an unsafe timeout, while release remains retryable after transient filesystem failures.

Fence locally committed session moves until server confirmation, advance location authority on unchanged list results, and restore same-origin preview element comments with the original cross-origin availability guard.

Add regression coverage for pre-clone locking, cross-host path convergence, foreign claims, release retries, shared lifetime leases, delayed session updates, unchanged list timestamps, and preview comment context. Validated 399 server tests, 255 UI tests, 133 Electron tests, 97 Tauri tests, typechecks, and the UI production build.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 11

  1. High packages/server/src/workspaces/repository-authority-path.ts:12 changes authority roots when an intermediate destination directory appears, allowing a second clone to use a different lock.
  2. High packages/server/src/workspaces/repository-lock-ownership.ts:62 requires exact mode 0700, which rejects shared authority roots on default WSL DrvFS mounts.
  3. High packages/server/src/workspaces/workspace-identity.ts:60 hashes mixed-case Windows and WSL drive paths differently before Git metadata exists.
  4. High packages/server/src/workspaces/workspace-lifetime-lease.ts:121 captures roots only before git init; later linked-worktree blocker scans can miss that live lease.
  5. Medium packages/server/src/server/instance-mutation-proxy.ts:243 caches and swallows a failed settlement release, losing the retry path after temporary filesystem recovery.
  6. Medium packages/server/src/workspaces/repository-lock-ownership.ts:283 uses non-retrying retirement after acquisition failure or cancellation and can strand a blocking claim.
  7. Medium packages/server/src/workspaces/repository-lock-ownership.ts:188 reports release success when heartbeat.json is missing even if the claim directory survives.
  8. Medium packages/ui/src/stores/session-location-authority.ts:81 compares superseded Windows directories literally, so equivalent slash/case spellings can bypass pending-move fencing.

Anchor pre-Git locks beneath the destination parent even when intermediate directories appear, converge Windows and WSL drive identities, and accept verified DrvFS permission projection without relaxing normal POSIX lock roots.

Discover pre-Git leases through linked worktrees, fail closed for nonstandard common directories, retain upstream mutation cleanup until release succeeds, and retry claim retirement without treating a missing heartbeat as a completed release.

Normalize superseded Windows session locations so equivalent slash, case, and trailing-separator spellings cannot bypass pending move fences. Covered each edge case with focused tests and validated 406 server tests, 61 browser UI tests, and root typechecks.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 12

  1. High repository release remains one-shot in callers outside the post-upstream tracker; exhausted transient retirement retries can strand live claims and instance admission.
  2. High repository-authority-path.ts canonicalizes only the parent, so a junction directly targeting an existing non-Git workspace uses disjoint lock and lease roots.
  3. High workspace-identity.ts assumes WSL drive mounts live under /mnt/; custom automount roots can produce different cross-host lock identities.
  4. High process-identity.ts host identity omits WSL distribution/PID namespace, so cloned distributions can misclassify each other as local and retire live claims.
  5. Medium failed acquisition and partial lease publication still discard claims after bounded rollback cleanup, leaving current-process claims live.
  6. Medium an unsandboxed preview can navigate top to a preview document, claim renderer authority, and invoke native directory open without the UI trusted-click check.
  7. Medium root session.updated events that omit workspaceID retain the prior worktree ID and create an impossible mixed location.
  8. Medium current-location confirmation still compares Windows directory spellings literally, so equivalent confirmations can be rejected and leave pending fences active.
  9. Medium preview-controlled labels, roles, and selectors enter backtick-delimited comment Markdown without sanitization, allowing prompt metadata injection.

Keep repository and lease cleanup pending until every ownership claim retires, canonicalize existing directory aliases, resolve custom WSL drive mounts, and distinguish WSL PID namespaces so live foreign owners cannot be retired locally.

Restrict Electron and Tauri renderer authority to shell documents and block top-level same-origin preview navigation before it can replace the shell. Preserve iframe preview networking while preventing history-based native capability bypasses.

Clear stale workspace IDs on directory-only moves, compare current Windows locations canonically, and normalize bounded preview metadata before building comment Markdown. Added focused coverage and validated 410 server tests, 69 UI tests, 133 Electron tests, 98 Tauri tests, and typechecks.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 13

  1. High workspace-identity.ts falls back to a distro path when wslpath times out for default /mnt/, diverging from WSL's Windows-drive lock identity.
  2. High opencode-replier.ts reacquires repository admission for a legacy YOLO reply while the synchronous prompt already holds it, deadlocking prompt and reply.
  3. High session-worktree-binding.ts does not treat Windows host roots and WSL-native roots as equivalent after a family move to root, blocking abort/reply routing.
  4. Medium worktrees.ts cannot resolve a WSL feature session from its authoritative workspaceId when host and native directory namespaces differ, blocking child session creation.
  5. Medium workspace-lifetime-lease.ts does not memoize concurrent release calls, so deletion and process-exit cleanup can race the shared claims array.
  6. Medium wsl-windows-drive.ts drops mounted Windows source prefixes, colliding C:\Projects mounted at /work with C:\ mounted at /mnt/c.
  7. Medium auto-accept-manager.ts captures a workspace ID before queued mutation admission; a concurrent family move makes the eventual YOLO persistence target stale.
  8. Medium manager.ts binds a shared launch to the first creator's abort signal, so that creator disconnect can cancel another active owner.

Let legacy permission replies use the instance control lane without reacquiring a repository lock held by their prompting mutation, and resolve YOLO persistence location only after queued move admission completes.

Preserve shared launches when one creator disconnects, memoize concurrent lifetime-lease release, retain Windows mount source prefixes, and safely converge default WSL drive identity when Windows-side path conversion is unavailable.

Route WSL-native root and feature sessions through authoritative workspace IDs while keeping host and native path equality namespace-aware. Validated 415 server tests, 68 browser UI tests, and root typechecks.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 14

  1. High queued instance exclusivity still blocks permission/question replies needed by an active synchronous prompt, deadlocking prompt and reply.
  2. High session abort is not admitted through the prompt control lane and waits on the repository lock held by the prompt it must stop.
  3. High UI workspace-list GETs send host directories while GET proxying does not convert them to WSL-native scope, returning the wrong OpenCode workspace inventory.
  4. Medium UI host/native matching only recognizes default /mnt/, so custom DrvFS roots and WSL UNC-native roots cannot map root or feature worktrees.
  5. Medium per-request abort signals no longer release ownership after shared launch reservation, allowing orphan launches or preventing remaining-owner cancellation.
  6. Medium reverse workspace-ID maps are non-reactive, so sessions rendered before synchronization can remain cached as root after mappings publish.

Allow permission, question, and abort controls to join an active prompt lane even when an exclusive repository mutation is queued. Disconnecting workspace creators now release only their own ownership while shared launches remain available to other callers.

Expose server-resolved OpenCode-native worktree directories and use them for workspace discovery and reactive session routing across default DrvFS, custom automounts, and WSL UNC repositories.

Cover control admission ordering, authoritative abort routing, request cancellation, native workspace-list scoping, and reactive UI mapping. Validated with 423 passing server tests, 72 focused browser tests, and root typecheck.
@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper cycle 15

Review target: 0a033b4c

  1. High The wildcard instance proxy permits direct POST /experimental/control-plane/move-session and DELETE /experimental/worktree calls, bypassing family validation, blocker checks, rollback, and metadata/map cleanup (packages/server/src/server/http-server.ts:561-600,804-892, packages/server/src/server/instance-mutation-proxy.ts:126-182, packages/server/src/server/routes/worktrees.ts:252-325).
  2. High Windows-hosted WSL instances still list and filter sessions using host paths, hiding native sessions and breaking strict status and interruption recovery (packages/ui/src/stores/session-api.ts:296-305,505-552, packages/ui/src/stores/instances.ts:205-217, packages/ui/src/stores/request-locations.ts:15-24, packages/server/src/server/http-server.ts:782-795).
  3. High A crashed cross-host owner permanently blocks recovery because foreign-host claims are treated as alive regardless of heartbeat age (packages/server/src/workspaces/process-identity.ts:45-75, packages/server/src/workspaces/repository-lock-ownership.ts:168-180,294-317, packages/server/src/workspaces/workspace-lifetime-lease.ts:101-120).
  4. High A nonzero git worktree remove can leave partial deletion, but rollback assumes the worktree remains intact and can move sessions back toward a missing checkout (packages/server/src/workspaces/worktree-deletion.ts:55-76, packages/server/src/workspaces/git-worktrees.ts:276-289, packages/server/src/workspaces/worktree-session-move.ts:230-237).
  5. Medium Tauri auth navigation can lose renderer authority after staged /login redirects through an unstaged location.replace("/") (packages/tauri-app/src-tauri/src/cli_manager.rs:1382-1398, packages/tauri-app/src-tauri/src/main.rs:237-270, packages/tauri-app/src-tauri/src/client_state/access.rs:32-54, packages/server/src/server/routes/auth-pages/login.html:122-123).
  6. Medium Valid POSIX repositories directly beneath root-owned writable directories such as /tmp/repo are rejected solely because the parent UID differs (packages/server/src/workspaces/repository-authority-path.ts:11-25, packages/server/src/workspaces/repository-mutation-lock.ts:12-15,72-79).
  7. Medium Worktree inventory, map, status, and in-flight loads survive instance destruction, allowing reused IDs to accept stale hydration or reject a current lower map revision (packages/ui/src/stores/worktrees.ts:16-28,43-59,83-132,287-293,358-400).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Conversation Categorization by Working Tree & Open File Explorer Support

1 participant